﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

using Excel = Microsoft.Office.Interop.Excel;
using System.Windows.Forms;
using DimensionData.Data2;
using System.Diagnostics;

namespace DimensionAddIn
{
    public class DocAddIn
    {
        public static Dictionary<string, DocAddIn> Instances = new Dictionary<string, DocAddIn>();

        public DocDimData Schema { get; set; }

        public List<DTree> DTree { get; set; }
        public DTree YDTree { get; set; }
        public DTree XDTree { get; set; }

        public List<PageDim> PageDims { get; set; }
        public bool IsChangedBySelf { get; set; }

        public DocData Matrix { get; set; }

        public DocAddIn(string sheetName)
        {
            PageDims = new List<PageDim>();
            IsChangedBySelf = false;
        }

        public void Init(DTree yTable, DTree xTable, List<PageDim> pageDim, List<FormulaRule> fRules, List<DataRefRule> rRules = null)
        {
            Schema = new DocDimData();
            Schema.YTree = yTable;
            Schema.XTree = xTable;
            Schema.PageDims = pageDim;
            Schema.FRules = fRules;
            if (rRules == null)
            {
                Schema.RRules = new List<DataRefRule>();
            }
            else
            {
                Schema.RRules = rRules;
            }

            YDTree = yTable;
            XDTree = xTable;
            PageDims = pageDim;
            Matrix = new DocData(yTable, xTable, pageDim);

            #region // 构建valuetable
            List<DRow> yRows = YDTree.Complanate2();
            List<DRow> xRows = XDTree.Complanate2();

            for (int yRowIndex = 0; yRowIndex < yRows.Count; yRowIndex++)
            {
                for (int xRowIndex = 0; xRowIndex < xRows.Count; xRowIndex++)
                {
                    string fullPath = string.Format("{0}{1}", yRows[yRowIndex].GetCodePath(), xRows[xRowIndex].GetCodePath());
                    Matrix.ValueTable.SetValue(fullPath, string.Empty);
                }
            }
            #endregion
        }

        public void OnCellValueChanged(Excel.Range target)
        {
            int targetCellRow = target.Row;
            int targetCellCol = target.Column;

            foreach (var pageDimPos in Matrix.VisualRect.PageDimPos)
            {
                if (pageDimPos.Row == targetCellRow && pageDimPos.Col == targetCellCol)
                {
                    if (!IsChangedBySelf)
                    {

                        Debug.WriteLine(string.Format("cell value change, in the page dim area: pos({0},{1})", targetCellRow, targetCellCol));
                        OnDimChanged(target);
                    }
                    return;
                }
            }

            if (IsChangedBySelf)
            {
                return;
            }

            if (Matrix.VisualRect.DataBeginRow <= targetCellRow
                && Matrix.VisualRect.DataBeginCol <= targetCellCol
                && Matrix.VisualRect.DataEndRow >= targetCellRow
                && Matrix.VisualRect.DataEndCol >= targetCellCol)
            {
                Debug.WriteLine(string.Format("cell value change, in the data area: pos({0},{1})", targetCellRow, targetCellCol));
                OnDataChanged(target);
            }
        }

        public void OnDimChanged(Excel.Range selection)
        {
            Excel.Worksheet sheet = selection.Worksheet;
            IsChangedBySelf = true;

            Windows.BusyIndicatorForm busyForm = new Windows.BusyIndicatorForm();
            busyForm.ShowMask(() =>
            {
                try
                {
                    #region 将excel上的公式单元格的值更新到，valuetable中
                    List<DRow> yRows = this.YDTree.Complanate2();
                    List<DRow> xRows = this.XDTree.Complanate2();
                    for (int yIndex = 0; yIndex < this.Matrix.VisualRect.YRowIndexList.Count; yIndex++)
                    {
                        for (int xIndex = 0; xIndex < this.Matrix.VisualRect.XRowIndexList.Count; xIndex++)
                        {
                            int yRowIndex = this.Matrix.VisualRect.YRowIndexList[yIndex];
                            int xRowIndex = this.Matrix.VisualRect.XRowIndexList[xIndex];
                            DRow yRow = yRows[yRowIndex];
                            DRow xRow = xRows[xRowIndex];

                            DRow uRow = yRow.Connect(xRow);
                            string codepath = uRow.GetCodePath();
                            Excel.Range xlsRange = sheet.XGetCell(this.Matrix.VisualRect.DataBeginRow + yIndex, this.Matrix.VisualRect.DataBeginCol + xIndex);
                            if ((bool)xlsRange.HasFormula == true)
                            {
                                string strValue = Convert.ToString(xlsRange.Text);

                                if (xlsRange.Errors[Excel.XlErrorChecks.xlEvaluateToError].Value)
                                {
                                    Debug.WriteLine(string.Format("{0},{1}存在公式错误,写入空值", xlsRange.Row, xlsRange.Column));
                                    this.Matrix.ValueTable.SetValue(codepath, null);
                                }
                                else
                                {
                                    this.Matrix.ValueTable.SetValue(codepath, xlsRange.XGetValue());
                                }
                            }
                        }
                    }
                    #endregion

                    #region // 获取所有的页面维度的值,刷新显示区域
                    for (int pdIndex = 0; pdIndex < PageDims.Count; pdIndex++)
                    {
                        int rangeCol = 2 * (pdIndex + 1) + 1;
                        string pageDimName = Convert.ToString(sheet.XGetCell(selection.Row, rangeCol).Value2);

                        PageDims[pdIndex].SelectedNames = GetAllNames(PageDims[pdIndex].DimData, pageDimName);
                    }
                    new DocRender(sheet).RenderContent(Schema, Matrix);
                    #endregion
                }
                catch
                {
                }
            });

            IsChangedBySelf = false;
        }

        private void ReLayout()
        {
            //MessageBox.Show(selection.Value2);
        }

        protected void OnDataChanged(Excel.Range selection)
        {
            List<DRow> yRows = Schema.YTree.Complanate2();
            List<DRow> xRows = Schema.XTree.Complanate2();
            int rangeRows = selection.Rows.Count;
            int rangeCols = selection.Columns.Count;

            for (int rIndex = 1; rIndex <= rangeRows; rIndex++)
            {
                for (int cIndex = 1; cIndex <= rangeCols; cIndex++)
                {
                    Excel.Range selRange = selection.XGetCell(rIndex, cIndex);
                    int targetCellRow = selRange.Row;
                    int targetCellCol = selRange.Column;

                    int deltaRow = targetCellRow - Matrix.VisualRect.DataBeginRow;
                    int deltaCol = targetCellCol - Matrix.VisualRect.DataBeginCol;

                    // 获取ydimrowindex, xdimrowindex
                    DRow yRow = yRows[Matrix.VisualRect.YRowIndexList[deltaRow]];
                    DRow xRow = xRows[Matrix.VisualRect.XRowIndexList[deltaCol]];
                    string codePath = string.Format("{0}{1}", yRow.GetCodePath(), xRow.GetCodePath());

                    object objValue = null;
                    if (selRange.Value2 != null && selRange.Value2 is double)
                    {
                        objValue = Convert.ToDouble(selRange.Value2);
                    }
                    else
                    {
                        objValue = Convert.ToString(selRange.Value2);
                    }

                    Debug.WriteLine(string.Format("update value table \"{0}\" \"{1}\"", codePath, objValue));
                    Matrix.ValueTable.SetValue(codePath, objValue);
                }
            }
        }

        /// <summary>
        /// 从维度结构中获取节点及其对应的所有子节点的名称列表
        /// </summary>
        /// <param name="data"></param>
        /// <param name="nodeName"></param>
        /// <returns></returns>
        public static List<string> GetAllNames(DData data, string nodeName)
        {
            List<string> names = new List<string>();
            DDataNode curNode = null;

            Stack<DDataNode> stack1 = new Stack<DDataNode>();
            foreach (var node in data.Nodes)
            {
                stack1.Push(node);
            }

            while (stack1.Count > 0)
            {
                DDataNode popNode = stack1.Pop();
                if (popNode.Name == nodeName)
                {
                    curNode = popNode;
                    break;
                }
                else
                {
                    foreach (var node in popNode.Nodes)
                    {
                        stack1.Push(node);
                    }
                }
            }

            Stack<DDataNode> stack2 = new Stack<DDataNode>();
            stack2.Push(curNode);
            while (stack2.Count > 0)
            {
                DDataNode popNode = stack2.Pop();
                names.Add(popNode.Name);
                foreach (var node in popNode.Nodes)
                {
                    stack2.Push(node);
                }
            }

            return names;
        }
    }
}
